package com.goldsprite.infinityworld.screens.examples.entity;

import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
import com.badlogic.gdx.scenes.scene2d.*;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.utils.*;
import com.badlogic.gdx.utils.viewport.*;
import com.goldsprite.gdxcore.entities.*;
import com.goldsprite.gdxcore.logs.*;
import com.goldsprite.infinityworld.entities.components.*;
import java.util.*;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.goldsprite.gdxcore.physics.RectCollider;
import com.goldsprite.gdxcore.screens.GScreen;
import com.goldsprite.gdxcore.utils.OrthoCamController;
import com.goldsprite.gdxcore.utils.sorts.EntitySort;
import com.goldsprite.infinityworld.assets.GlobalAssets;
import com.goldsprite.infinityworld.entities.randommap.BlockId;
import com.goldsprite.infinityworld.ui.EditorLayout;
import com.goldsprite.simplexnoise.SimplexNoise2D;
import com.goldsprite.utils.math.Vector2;
import com.goldsprite.gdxcore.physics.CollInfo;

public class SimplePhysicsExampleScreen extends GScreen{
	//世界参数
	private float worldWidth = 960, worldHeight = 540;
	private Viewport viewport;
	private OrthographicCamera uiCam;

	//ui触控渲染
	private Skin skin;
	private Stage stage;

	//实体组
	private MyPhysicsGameWorld world;


	@Override
	public void create() {
		initEssentials();

		EditorLayout editorLayout = initEditorLayout();
		stage.addActor(editorLayout);
	}

	private void initEssentials() {
		uiCam = new OrthographicCamera();
		viewport = new FitViewport(worldWidth, worldHeight, uiCam);
		viewport.apply(true);

		skin = GlobalAssets.getInstance().editorSkin;

		stage = new Stage(viewport);
		getImp().addProcessor(stage);
	}

	private EditorLayout initEditorLayout() {
		// 游戏视图区域
		WidgetGroup gameTable = new WidgetGroup();
		//游戏世界Group
		GameWorldGroup gameCanvasGroup = new GameWorldGroup();
		gameCanvasGroup.setScreenCam(stage.getCamera());
		gameCanvasGroup.setScreen(this);
		gameTable.addActor(gameCanvasGroup);

		world = new MyPhysicsGameWorld();

		EditorLayout editorLayout = new EditorLayout();
		editorLayout.init(this, skin, gameTable, ()->{
			if (!world.gameInitialized) {
				world.initGameWorld(skin, gameCanvasGroup);
			}
		});

		return editorLayout;
	}



	@Override
	public void render(float delta) {
		ScreenUtils.clear(0.35f, 0.35f, 0.35f, 1);

		stage.act(delta);
		stage.draw();
	}


	private static class MyPhysicsGameWorld extends GameWorld {
		public boolean gameInitialized;

		private Skin skin;

		private Touchpad rocker;

		public static MyAnimatorEntity role;
		public static TmpBlock playerRect;

		//功能组件
		private RockerRoleController roleCtrl;
		private OrthoCamController worldCamCtrl;
		private FollowCameraContoller followCamCtrl;

		//初始化游戏世界
		public void initGameWorld(Skin skin, GameWorldGroup gameCanvasGroup) {
			this.skin = skin;

			GameWorld world = this;
			world.setFillParent(true);
			gameCanvasGroup.addActor(world);
			world.setWorldGroup(gameCanvasGroup);
			world.init(960, 540);

			SortMap map = new SortMap();
			map.init();
			world.addEntity(map);

			//玩家
			createPlayer();
			world.addEntity(role);
			playerRect = new TmpBlock(){
				public float z(){
					float downY = originPos.y - renderSize.y/2;
					float footPivotOffset = role.getFootPivotOffset().y;
					return downY+footPivotOffset;
				}
			};
			//tmpBlock依赖部分
			playerRect.setSorter(map.entSorter);
			playerRect.renderSize.set(role.getSize());
			map.objects.add(playerRect);
			//动画实体依赖部分
			role.setPlayerRect(playerRect);
			role.setEntSorter(map.entSorter);

			//触控ui部分
			createGui();

			//摇杆移动组件
			roleCtrl = new RockerRoleController(role, rocker);
			roleCtrl.roleMoveVel = 180;
			boolean[] isUIEvent = {false};
			//地图相机控制组件
			worldCamCtrl = new OrthoCamController(worldCam, isUIEvent);
			getWorldGroup().screen.getImp().addProcessor(worldCamCtrl);

			//跟随相机组件
			followCamCtrl = new FollowCameraContoller(world.transCam, rocker,  role, 2.4f);

			gameInitialized = true;
		}

		private void createGui(){
			//摇杆
			float size = 180, margin = 10;
			rocker = new Touchpad(0, skin);
			rocker.setBounds(margin, margin, size, size);

			Table gMenu = new Table(skin);
			gMenu.top().left();
			gMenu.setPosition(margin, getWorldGroup().getHeight()-margin, Align.topLeft);

			//跟随相机开关
			TextButton toggleFollowCamBtn = new TextButton("跟随相机(开)", skin);
			toggleFollowCamBtn.addListener(new ClickListener(){
					boolean enanled = true;
					public void clicked(InputEvent ev, float x, float y){
						enanled = !enanled;
						followCamCtrl.enableFollowCam = enanled;
						toggleFollowCamBtn.setText(enanled ?"跟随相机(开)" :"跟随相机(关)");
					}
				});

			//跟随相机缩放开关
			TextButton toggleFollowCamSclBtn = new TextButton("跟随相机缩放(开)", skin);
			toggleFollowCamSclBtn.addListener(new ClickListener(){
					boolean enanled = true;
					public void clicked(InputEvent ev, float x, float y){
						enanled = !enanled;
						followCamCtrl.enableFollowCamScl = enanled;
						toggleFollowCamSclBtn.setText(enanled ?"跟随相机缩放(开)" :"跟随相机缩放(关)");
					}
				});

			//debugGizmos绘制开关
			TextButton debugGizmosBtn = new TextButton("绘制Gizmos(开)", skin);
			debugGizmosBtn.addListener(new ClickListener(){
					boolean enanled = true;
					public void clicked(InputEvent ev, float x, float y){
						enanled = !enanled;
						GameWorld.enableDebugGizmos = enanled;
						debugGizmosBtn.setText(enanled ?"绘制Gizmos(开)" :"绘制Gizmos(关)");
					}
				});

			gMenu.add(toggleFollowCamBtn).space(margin);
			gMenu.add(toggleFollowCamSclBtn);
			gMenu.add(debugGizmosBtn);

			getWorldGroup().addActor(rocker);
			getWorldGroup().addActor(gMenu);
		}

		private void createPlayer(){
			String roleTexPath = "roles/Soldier.png";
			Texture roleTex = new Texture(Gdx.files.internal(roleTexPath));

			//统一动画速度
			float animPerVel = 1;
			// 创建动画器并导入源材质与设置帧单位大小
			role = new MyAnimatorEntity(roleTex, 100, 100);
			role.bodyBound.set(15, 18);
			role.footPivot.set(50, 43);
			//设置动画
			role.addAnimation("Idle", 0, 6, animPerVel / 6);
			role.addAnimation("Walk", 1, 8, animPerVel / 8);
			role.setCurAnimation("Idle");
			//设置实体大小
			role.setScl(4f);
			Vector2 startPos = new Vector2(200, 200);
			role.setCenterPosition(startPos.x+role.getBodySize().x/2, startPos.y+role.getBodySize().y/2);
		}

		@Override
		public void act(float delta) {
			if(gameInitialized){
				super.act(delta);

				//角色控制
				roleCtrl.update(delta);
				followCamCtrl.update(delta);
			}
		}

		@Override
		public void draw(Batch batch, float parentAlpha) {
			if(gameInitialized)
				super.draw(batch, parentAlpha);
		}

	}


	public static class MyAnimatorEntity extends AnimatorEntity{

		public MyAnimatorEntity(Texture animTextures, int frameWidth, int frameHeight) {
			super(animTextures, frameWidth, frameHeight);
		}


		@Override
		public void act(float delta) {
			//逻辑更新：动画
			super.act(delta);
			updateLogic(delta);
		}

		private void updateLogic(float delta) {
			//同步数据：动画帧，位置, 物理框
			playerRect.region = getCurFrame();
			//playerRect.originPos.set(getCenterPosition());
			playerRect.originPos.set(getFootPivotOffset()).add(getPosition());

			playerRect.rcoll.bound.halfSize.set(getBodySize().x/2*0.6f, getBodySize().y/2*0.25f);
			playerRect.rcoll.bound.center.set(
				getPosition().x+getFootPivotOffset().x, 
				playerRect.z()+playerRect.rcoll.bound.halfSize.y);

			//排序器
			if(playerRect.isSort()){
				entSorter.sort();
			}
		}

		@Override
		public void render(Batch batch, float delta) {
			//这里置空，使用sortMap代理绘制逻辑
		}

	}


	private static class SortMap extends Renderable{
		private EntitySort<TmpBlock> entSorter;
		private Array<TmpBlock> ground = new Array<>();
		private Array<TmpBlock> objects = new Array<>();
		private TmpBlock tmpBlock;
		private float delta;


		public void init(){
			initEnts();
		}

		private void initEnts() {
			//排序器
			entSorter = new EntitySort<TmpBlock>(objects, false);
			//生成材质
			Texture tiles = new Texture(Gdx.files.internal(BlockId.cellTexturesPath));
			TextureRegion[][] splitTiles = TextureRegion.split(tiles, BlockId.regionSplit, BlockId.regionSplit);
			int gridCountX = tiles.getWidth()/BlockId.regionSplit;
			int gridCountY = tiles.getHeight()/BlockId.regionSplit;
			//生成地图
			spawnMap(gridCountX, gridCountY, splitTiles);
			//测试方块
			/*BlockId tmpId = BlockId.House;
			TmpBlock tmpBlock = newBlock(splitTiles[tmpId.y][tmpId.x], 300, 200, 64, true);
			tmpBlock.setSorter(entSorter);
			BlockId tmpId2 = BlockId.BeachTree;
			TmpBlock tmpBlock2 = newBlock(splitTiles[tmpId2.y][tmpId2.x], 300+64+10, 200, 64, true);
			tmpBlock2.setSorter(entSorter);*/
			/*tmpId = BlockId.Tree2;
			tmpBlock = newBlock(splitTiles[tmpId.y][tmpId.x], 300+(64+10)*2, 200, 64, true);
			tmpBlock.setSorter(entSorter);*/

		}

		private void spawnMap(int gridCountX, int gridCountY, TextureRegion[][] splitTiles){
			//随机生成元素
			float scl = 0.4f, xRange = 100*scl, yRange = 100*scl;
			float blockRenderSize = 64;
			//生成有序随机地图
			int startX = 530, startY = 575;
			int mapWidth = 50, mapHeight = 50;
			for(int l=0;l<2;l++){
			 for(int y=mapHeight-1;y>=0;y--){
			 for(int x=0;x<mapWidth;x++){
			 BlockId blockId = getRanBlock(startX+x, startY+y, l);
			 TextureRegion region = splitTiles[blockId.y][blockId.x];
			 if(blockId.equals(BlockId.Air)) continue;
			 TmpBlock block = newBlock(region, x*blockRenderSize, y*blockRenderSize, blockRenderSize, l==1);
			 block.setSorter(entSorter);
			 if(l==0) ground.add(block);
			 }
			 }
			 }
			//生成随机方块列表
			for(int i=0;i<100;i++){
				//随机参数
				double ran = new Random().nextDouble();
				int ranIndexX = (int)(ran*gridCountX);
				double ran2 = new Random().nextDouble();
				int ranIndexY = (int)(ran2*gridCountY);
				TextureRegion region = splitTiles[ranIndexY][ranIndexX];
				//填充数据
				TmpBlock block = newBlock(
					region, 
					(int)(new Random().nextInt((int)xRange)*blockRenderSize), 
					(int)(new Random().nextInt((int)yRange)*blockRenderSize), 
					64, true
				);
				block.setSorter(entSorter);
			}
		}

		private TmpBlock newBlock(TextureRegion region, float x, float y, float renderSize, boolean join) {
			TmpBlock block = new TmpBlock();
			block.region = region;
			block.originPos.x = x;
			block.originPos.y = y;
			block.rcoll.bound.set(x, y, renderSize/2, renderSize/2);
			block.renderSize.set(renderSize);
			if(join) objects.add(block);
			return block;
		}

		@Override
		public void render(Batch batch, float delta) {
			this.delta = delta;

			//地面
			for(TmpBlock block : ground){
				block.draw(batch);
			}
			
			//物体
			MyPhysicsGameWorld.role.getPosition().add(MyPhysicsGameWorld.playerRect.rcoll.velocity);
			for(TmpBlock obj : objects){
				//碰撞
				//if(obj == MyPhysicsGameWorld.playerRect) 
				//绘制
				obj.draw(batch);
			}
		}

		Vector2 tmpVec = new Vector2();
		private void collisionDetection(TmpBlock self, Array<TmpBlock> objects) {
			CollInfo minCollInfo = null;
			for(int i=0;i<objects.size;i++){
				TmpBlock otherCollider = objects.get(i);
				if(otherCollider == self) continue;

				RectCollider rcoll = self.rcoll;
				RectCollider rcoll2 = otherCollider.rcoll;
				CollInfo curColl = rcoll.overlap(rcoll2);
				if(curColl.isCollision){
					if(minCollInfo == null || (minCollInfo!=null && curColl.distance<minCollInfo.distance)){
						minCollInfo = curColl;
					}
				}
				//rcoll.collInfo.isCollision = rcoll.bound.intersects(rcoll2.bound);//单纯aabb
			}

			boolean isPlayer = self == MyPhysicsGameWorld.playerRect;
			boolean isWalk = MyPhysicsGameWorld.role.getCurAnimName().equals("Walk");
			TmpBlock player = MyPhysicsGameWorld.playerRect;

			if(isPlayer){
				if(minCollInfo != null){
					self.rcoll.collInfo.set(minCollInfo);
					self.rcoll.velocity.set(minCollInfo.newVelocity);
				}
				else self.rcoll.collInfo.reset();
				if(isWalk) LogViewerService.logInfo("玩家速度："+tmpVec.set(player.rcoll.velocity).div(delta));
				RealtimeInfoViewer.setInfo(2, "玩家碰撞信息："+player.rcoll.collInfo);
				//应用玩家速度
				//MyPhysicsGameWorld.role.getPosition().add(player.rcoll.velocity);
				//player.rcoll.velocity.set(0);
			}
		}

		@Override
		public void renderDebug(ShapeRenderer gizmos, float delta){
			//drawDebug
			for(TmpBlock obj : objects){
				obj.drawDebug(gizmos, "center");
				obj.drawDebug(gizmos, "zPoint");
				//obj.drawDebug(gizmos, "bound");
				obj.drawDebug(gizmos, "collBound");
			}
		}

		private int minHigh = -64, maxHigh = 64;
		private BlockId getRanBlock(int x, int y, int type){
			double noise = SimplexNoise2D.getNorNoise(x, y, 0.02, 5, 0.45);
			double height = mapNoiseToHeight(noise, minHigh, maxHigh);
			BlockId blockId = getBlockIdForHeight(height);

			//生成obj(树等)
			BlockId objId = BlockId.Air;
			//ran决定出现树的覆盖率
			float ran = new Random((long)(noise*1_000_000)).nextFloat();
			//草地树
			if(height>40+off){
				if(ran > 0.5f){
					if(ran < 0.65f) objId = BlockId.Tree;
					else objId = BlockId.Tree2;
				}
			}
			//沙滩树
			if(height>28+off+1 && height<34+off){
				if(ran > 0.8f)objId = BlockId.BeachTree;
			}

			return type == 0 ?blockId :objId;
		}

		////旧版代码
		public int off = -22;//越小目标高度面积越大
		// 高度映射表：每个高度范围对应一个BlockId
		public TreeMap<Integer, BlockId> heightMap = new TreeMap<Integer, BlockId>(){{
				//put(64+off, BlockId.Air);
				put(40+off, BlockId.Grass);
				put(38+off, BlockId.Grass2);
				put(34+off, BlockId.Sand);
				put(28+off, BlockId.Water);
				put(24+off, BlockId.Water2);
				put(18+off, BlockId.Water3);
				put(10+off, BlockId.Water4);
			}};
		public TreeMap<Integer, BlockId> obj_heightMap = new TreeMap<Integer, BlockId>(){{
				//put(64+off, BlockId.Air);
				put(45+off, BlockId.Tree);
				put(40+off, BlockId.Air);
			}};

		// 将噪声值映射到指定的高度区间, 接收值区间: 0 ~ 1
		private double mapNoiseToHeight(double noiseValue, int minHeight, int maxHeight) {
			return minHeight + noiseValue * (maxHeight - minHeight);
		}

		// 根据高度值查找对应的BlockId
		private BlockId getBlockIdForHeight(double height) {
			Integer key = heightMap.ceilingKey((int) height);  // 向上对齐到最近的高度
			if (key == null) key = heightMap.lastKey();
			return heightMap.get(key);
		}
	}

}
